package com.yaolonga.itfc.manager.core;

import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.json.JSONUtil;
import com.yaolonga.itfc.manager.core.exception.CmdExecuteException;
import com.yaolonga.itfc.manager.core.utils.MapUtil;
import com.yaolonga.itfc.manager.core.utils.Strings;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.Consumer;

/**
 * @Author: yaolong
 * @CreateTime: 2024-10-17  10:26
 * @Description: 抽象网络接口提供者
 * @Version: 1.0
 */
@Slf4j
public abstract class AbstractNetworkInterfaceManager implements NetworkInterfaceManager {
    /**
     * 默认语言环境
     */
    @Getter
    private final Locale locale;

    /**
     * 语言配置文件map对象（网络接口）
     */
    private final Map<String, Object> langConf;


    /**
     * 语言配置文件路径
     */
    private final static String LANGUAGE_CONF_PATH = "language/%s/%s.json";

    /**
     * 网络接口语言配置对象访问路径
     */
    private final static String NET_INTERFACE_CONF_PATH = "%s.interface.netInterface";


    protected AbstractNetworkInterfaceManager() {
        this.locale = Locale.getDefault();
        this.langConf = getLangConf(getNetInterfaceConfPath());
    }

    public <T> T getLangConfValue(String key, Class<T> type) {
        return MapUtil.getValueByPath(langConf, key, type);
    }

    @SuppressWarnings("all")
    private Map<String, Object> getLangConf(String path) {
        // 获取资源文件
        String resource = NetworkInterfaceHelper.getResource(() -> new ClassPathResource(String.format(LANGUAGE_CONF_PATH,getSystemType().name(), locale), this.getClass().getClassLoader()));
        Map<String, Object> languageMap = null;
        try {
            languageMap = JSONUtil.parseObj(resource);
        } catch (Exception e) {
            log.error("json转换异常： {} {}", e.getMessage(), resource);
            return new HashMap<String, Object>();
        }
        return MapUtil.getValueByPath(languageMap, path, Map.class);
    }


    /**
     * 获取命令前缀（每个操作系统的命令前缀是不一样的额，比如win: cmd /c, linux bin/sh/ -c）
     *
     * @return
     */
    protected List<String> getPrefixCommands() {
        List<String> commands = new ArrayList<>();

        switch (getPlatformType()) {
            case windows:
                commands.add("cmd");
                commands.add("/c");
                break;
            case macos:
                commands.add("/bin/sh");
                commands.add("-c");
                break;
            case linux:
            default:
                break;
        }
        return commands;
    }

    protected String execCmdAndReturn(String cmd) {
        String[] split = cmd.split("\\s+");
        return execCmdAndReturn(Arrays.asList(split), null);
    }

    protected String execCmdAndReturn(List<String> commands) {
        return execCmdAndReturn(commands, null);
    }

    protected String execCmdAndReturn(List<String> _commands, Consumer<OutputStream> inputCsm) {
        List<String> commands = getPrefixCommands();
        commands.addAll(_commands);

        Charset charset = getCharset();
        // 执行命令并获取结果
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(commands);
            Process process = processBuilder.start();
            // 获取命令的输入流和输出流
            OutputStream stdin = process.getOutputStream();
            InputStream stdout = process.getInputStream();
            InputStream stderr = process.getErrorStream();
            // 获取输出
            String output = readStream(stdout, charset);

            if (inputCsm != null) {
                inputCsm.accept(stdin);
            }
            // 等待进程结束
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                return output;
            } else {
                String error = readStream(stderr, charset);
                if (Strings.isNotBlank(output)) {
                    throw new IOException(output);
                }
                throw new IOException("Command execution failed with exit code " + exitCode + " and error：" + error);
            }
        } catch (IOException e) {
            log.error("执行命令[{}]异常： {}", commands, e.getMessage(), e);
            throw new CmdExecuteException(String.format("执行命令[%s]异常： %s", Strings.join(commands, ' '), e.getMessage()), e);
        } catch (InterruptedException e) {
            throw new CmdExecuteException(Strings.join(commands, ' '), e);
        }
    }


    protected Charset getCharset() {
        return Charset.defaultCharset();
    }

    protected Process execCmd(String cmd) {
        String[] split = cmd.split("\\s+");
        return execCmd(Arrays.asList(split));
    }

    protected Process execCmd(List<String> commands) {
        List<String> prefixCommands = getPrefixCommands();
        prefixCommands.addAll(commands);

        // 执行命令并获取结果
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(prefixCommands);
            return processBuilder.start();
        } catch (IOException e) {
            log.error("执行命令[{}]异常： {}", prefixCommands, e.getMessage(), e);
            throw new CmdExecuteException(String.format("执行命令[%s]异常： %s", Strings.join(prefixCommands, ' '), e.getMessage()), e);
        }
    }


    private String readStream(InputStream inputStream, Charset charset) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charset));
        StringBuilder builder = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            builder.append(line);
            builder.append(System.getProperty("line.separator"));
        }
        return builder.toString();
    }


    private String getNetInterfaceConfPath() {
        return String.format(NET_INTERFACE_CONF_PATH, getSystemType());
    }


}
